﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Resources;
using System.Diagnostics.Contracts;
using System.Reflection;

namespace RPGMapRevealer
{
    /// <summary>
    /// The main Map window
    /// </summary>
    public partial class MainMapWindow : Form
    {
        /// <summary>
        /// Constructs the main Map window
        /// </summary>
        public MainMapWindow()
        {
            InitializeComponent();
            mapServer.Start();
        }

        private MapServer mapServer = new MapServer();
        private readonly ResourceManager Resources = new ResourceManager("MapRevealer.LocalizedStrings", Assembly.GetExecutingAssembly());

        private void ShowMsg(String code)
        {
            MessageBoxOptions opt = MessageBoxOptions.DefaultDesktopOnly;
            if (RightToLeft == System.Windows.Forms.RightToLeft.Yes)
            {
                opt |= MessageBoxOptions.RightAlign | MessageBoxOptions.RtlReading;
            }
            String text = GetText(code + "_Text");
            String caption = GetText(code + "_Caption");
            MessageBox.Show(text, caption, MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, opt);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private String GetText(String key)
        {
            try { return Resources.GetString(key); }
            catch (Exception) { return "!!!" + key; }
        }

        private void buttonAnalyze_Click(object sender, EventArgs e)
        {
            Bitmap publicImage = null;
            Bitmap secretImage = null;

            if (String.IsNullOrWhiteSpace(fileSelectorPublic.FileName))
            {
                ShowMsg("publicImageNull");
                return;
            }

            publicImage = (Bitmap)Bitmap.FromFile(fileSelectorPublic.FileName);
            if (!String.IsNullOrWhiteSpace(fileSelectorSecret.FileName))
            { secretImage = (Bitmap)Bitmap.FromFile(fileSelectorSecret.FileName); }
            if (secretImage == null)
            { secretImage = publicImage; }

            publicImage.SetResolution(96, 96);
            secretImage.SetResolution(96, 96);

            DirectoryInfo saveTiles = GetDefaultTilesFolder();

            if (!saveTiles.Exists)
            { saveTiles.Create(); }
            else
            {
                foreach (FileInfo file in saveTiles.GetFiles())
                { if (file != null && file.Extension == ".jpg") { file.Delete(); } }
            }

            MapInfo mapInfo = new MapInfo() { GridConfig = gridConfigUserControl1.GridConfig };

            mapInfo.TileFolder = saveTiles;
            mapInfo.PublicImage = publicImage;
            mapInfo.SecretImage = secretImage;

            if (publicImage.Width != secretImage.Width || publicImage.Height != secretImage.Height)
            {
                ShowMsg("publicSecretDimensionsDiffer");
                return;
            }


            AsyncAnalysisReport result = TileAnalyser.BeginAnalyzeWholeImage(publicImage, secretImage, mapInfo, saveTiles);
            AnalysisProgressDialog waitTillDone = new AnalysisProgressDialog();
            waitTillDone.AsyncResult = result;
            waitTillDone.ShowDialog();

            useThisMap(mapInfo);
        }

        private DirectoryInfo GetDefaultTilesFolder()
        {
            String appPath = getWritableFolder().FullName;
            if (appPath == null)
            { throw new CodeContractsException("This should never happen, how the heck are we even running without a path?"); }

            String tilePath = Path.Combine(appPath, "Tiles");
            DirectoryInfo path = new DirectoryInfo(tilePath);
            if (!path.Exists)
            { path.Create(); }
            return path;
        }

        [ContractInvariantMethod]
        private void InvariantMethod()
        {
            Contract.Invariant(Resources != null);
            Contract.Invariant(fileSelectorPublic != null);
            Contract.Invariant(fileSelectorSecret != null);
            Contract.Invariant(mapPreviewUserControl1 != null);
            Contract.Invariant(panel1 != null);
            Contract.Invariant(panel2 != null);
            Contract.Invariant(label1 != null);
            Contract.Invariant(label2 != null);
            Contract.Invariant(groupBoxImageFiles != null);
            Contract.Invariant(gridConfigUserControl1 != null);
            Contract.Invariant(toolTips != null);
            Contract.Invariant(buttonAnalyze != null);
        }

        private void toolStripButtonLoad_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                ofd.Title = "Load an existing map project";
                ofd.Filter = "RPG Map file|*.rpgmap";
                if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    useThisMap(MapInfoSerializer.Deserialize(ofd.FileName, GetDefaultTilesFolder()));
                    lockImageControls(true);
                }
            }
        }

        private void toolStripButtonSave_Click(object sender, EventArgs e)
        {
            using (SaveFileDialog sfd = new SaveFileDialog())
            {
                sfd.Title = "Save current map project";
                sfd.Filter = "RPG Map file|*.rpgmap";
                if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    MapInfoSerializer.Serialize(mapServer.MapInfo, sfd.FileName);
                    lockImageControls(true);
                }
            }
        }

        private void toolStripButtonNew_Click(object sender, EventArgs e)
        {
            MapInfo map = new MapInfo();
            map.TileFolder = GetDefaultTilesFolder();
            lockImageControls(false);
            useThisMap(map);
        }

        private void lockImageControls(bool dolock)
        {
            fileSelectorPublic.Enabled = !dolock;
            fileSelectorSecret.Enabled = !dolock;
            buttonAnalyze.Enabled = !dolock;
            gridConfigUserControl1.Enabled = !dolock;
            splitContainer1.Panel1Collapsed = dolock;
        }

        private void useThisMap(MapInfo map)
        {
            mapPreviewUserControl1.MapInfo = map;
            mapServer.MapInfo = map;
        }

        private void MainMapWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            autosave();
            mapServer.Stop();
        }

        private void timerAutoSave_Tick(object sender, EventArgs e)
        {
            autosave();
        }

        private void toolStripButtonKillTheLights_Click(object sender, EventArgs e)
        {
            if (mapServer.MapInfo != null)
            {
                foreach (Tile tile in mapServer.MapInfo.Tiles)
                {
                    tile.LightLevel = 0;
                }
                mapServer.MapInfo.RecalculateLightAndLineOfSight();
            }
        }
        private DirectoryInfo getWritableFolder()
        {
            DirectoryInfo path = new DirectoryInfo(Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RPGMapRevealer"));
            if (!path.Exists)
            { path.Create(); }
            return path;
        }

        private FileInfo getAutosaveFile()
        {
            return new FileInfo(Path.Combine(getWritableFolder().FullName, "autosave.automaprpg"));
        }

        private object autosaveLock = new object();
        private void autosave()
        {
            lock (autosaveLock)
            {
                try
                {
                    if (mapServer.MapInfo != null)
                    {
                        MapInfoSerializer.Serialize(mapServer.MapInfo, getAutosaveFile());
                    }
                }
                catch { }
            }
        }

        private void restoreAutosave()
        {
            lock (autosaveLock)
            {
                try
                {
                    FileInfo autosave = getAutosaveFile();
                    if (autosave.Exists)
                    {
                        MapInfo map = MapInfoSerializer.Deserialize(autosave, GetDefaultTilesFolder());
                        useThisMap(map);
                        lockImageControls(true);
                    }
                }
                catch { }
            }
        }

        private void MainMapWindow_Load(object sender, EventArgs e)
        {
            restoreAutosave();
        }

        private void toolStripButtonChangeLightSource_Click(object sender, EventArgs e)
        {
            using (LightAdjustDialog lad = new LightAdjustDialog())
            {
                lad.Value = currentLightLevel;
                if (lad.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    currentLightLevel = lad.Value;
                    mapPreviewUserControl1.CustomLightLevel = currentLightLevel;
                }
            }
        }
        private int currentLightLevel = 8;

        private void toolStripButtonEnableWallEditMode_Click(object sender, EventArgs e)
        {
            toolStripButtonDisableWallEditMode.Visible = true;
            toolStripButtonEnableWallEditMode.Visible = false;
            mapPreviewUserControl1.WallEditMode = true;
        }

        private void toolStripButtonDisableWallEditMode_Click(object sender, EventArgs e)
        {
            toolStripButtonDisableWallEditMode.Visible = false;
            toolStripButtonEnableWallEditMode.Visible = true;
            mapPreviewUserControl1.WallEditMode = false;
        }

        private void toolStripButtonDoNotAnimatePlayerMovement_Click(object sender, EventArgs e)
        {
            mapPreviewUserControl1.AnimatePlayerMovement = false;
            toolStripButtonAnimatePlayerMovement.Visible = true;
            toolStripButtonDoNotAnimatePlayerMovement.Visible = false;
        }

        private void toolStripButtonAnimatePlayerMovement_Click(object sender, EventArgs e)
        {
            mapPreviewUserControl1.AnimatePlayerMovement = true;
            toolStripButtonAnimatePlayerMovement.Visible = false;
            toolStripButtonDoNotAnimatePlayerMovement.Visible = true;
        }

    }
}
